//package 题目集.扫描线;
//
//import java.util.Arrays;
//import java.util.Scanner;
//
///**
// * https://www.luogu.com.cn/problem/P5490 假设有一根平行于x轴的线，从y的0位置向上扫描。
// * 把矩形的底边和顶边都看作一个区间操作。 底边操作：将x1~x2范围全部设置为1 顶边操作：将x1~x2范围全部设置为0
// * 当然，顶边操作不能把之前所有的底边都x1~x2得范围都设置为0 例如：有两个矩左下角点与右上角点为 矩形1（2，3）（5，6），矩形2（3，4）（4，6）
// * 很显然，矩形2是嵌在矩形1内部的，当扫描到矩形2的顶边时不能将这个区间化为0。 所以需要额外懒下一个东西：区间被操作的次数.
// * 这题的离散化不会做
// */
//public class ch03_矩形面积并 {
//	static int maxn = (int) (1e5 + 10);
//	static int[][] ops = new int[maxn][]; // 记录所有的事件 ，0:l,1:r,2：y，3：op
//	static int[] sort; // x轴的离散化
//	static int n, total, size, tn;
//	static Tree[] tr;
//
//	public static void main(String[] args) {
//		Scanner sc = new Scanner(System.in);
//		n = sc.nextInt();
//		sort = new int[2 * n + 1];
//		for (int i = 0; i < n; i++) {
//			int x1 = sc.nextInt();
//			int y1 = sc.nextInt();
//			int x2 = sc.nextInt();
//			int y2 = sc.nextInt();
//			sort[total + 1] = x1;
//			ops[total++] = new int[] { x1, x2, y1, 1 };
//			sort[total + 1] = x2;
//			ops[total++] = new int[] { x1, x2, y2, -1 };
//		}
//		Arrays.sort(ops, 0, total, (a, b) -> a[2] - b[2]);
//		size = distinct(sort);
//		tn = (int) Math.pow(2, 1 + Math.ceil(Math.log(size) / Math.log(2)));
//		tr = new Tree[tn];
//		sort[0] = sort[1];
//		build(1, 1, size);
//		int preY = ops[0][2];
//		long sum = 0;
//		for (int i = 0; i < total; i++) {
//			sum += (ops[i][2] - preY) * tr[1].cnt;
//			preY = ops[i][2];
//			int l = Arrays.binarySearch(sort, 1, size + 1, ops[i][0]);
//			int r = Arrays.binarySearch(sort, 1, size + 1, ops[i][1]);
//			add(1, l, r, ops[i][3]);
//		}
//		System.out.println(sum);
//	}
//
//	public static int distinct(int[] sort) {
//		Arrays.sort(sort, 1, sort.length);
//		int cnt = 1;
//		sort[cnt++] = sort[1];
//		for (int i = 2; i < sort.length; i++) {
//			if (sort[i] != sort[i - 1]) {
//				sort[cnt++] = sort[i];
//			}
//		}
//		return cnt - 1;
//	}
//
//	private static void build(int i, int l, int r) {
//		tr[i] = new Tree(l, r, sort[r] - sort[l - 1]);
//		if (l == r) {
//			return;
//		}
//		int m = l + r >> 1;
//		build(i << 1, l, m);
//		build(i << 1 | 1, m + 1, r);
//	}
//
//	public static void add(int i, int l, int r, int op) {
//		if (l <= tr[i].l && tr[i].r <= r) {
//			tr[i].lazy(op);
//		} else {
//			int m = tr[i].l + tr[i].r >> 1;
//			if (l <= m) {
//				add(i << 1, l, r, op);
//			}
//			if (m < r) {
//				add(i << 1 | 1, l, r, op);
//			}
//		}
//		pull(i);
//	}
//
//	public static void pull(int i) {
//		if (tr[i].op > 0) {
//			tr[i].cnt = tr[i].len;
//		} else {
//			int l = i << 1;
//			int r = l | 1;
//			tr[i].cnt = 0;
//			if (l < tn && tr[l] != null) {
//				tr[i].cnt += tr[l].cnt;
//			}
//			if (r < tn && tr[r] != null) {
//				tr[i].cnt += tr[r].cnt;
//			}
//		}
//	}
//
//	static class Tree {
//		int l, r;
//		int len; // 区间的实际长度
//		int cnt, op; // 1的个数和操作的次数
//
//		public Tree(int l, int r, int len) {
//			this.l = l;
//			this.r = r;
//			this.len = len;
//		}
//
//		public void lazy(int op) {
//			this.op += op;
//			cnt = op > 0 ? len : 0;
//		}
//
//		@Override
//		public String toString() {
//			return "Tree [l=" + l + ", r=" + r + ", len=" + len + ", cnt=" + cnt + ", op=" + op + "]";
//		}
//
//	}
//}
